/*
 * MIT License
 *
 * Copyright (c) 2020 wen.gu <454727014@qq.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

/******************************************************************************
 * Name: dog_log.h
 *
 * Purpose: log trace wraper for puppy dog
 *
 * Developer:
 *   wen.gu , 2020-08-19
 *
 * TODO:
 *
 ******************************************************************************/

/******************************************************************************
 **    INCLUDES
 ******************************************************************************/
#ifndef __DOG_LOG_H__
#define __DOG_LOG_H__

#include <string>
#include <functional>
#include <memory>

#include "dog_types.h"
/******************************************************************************
 **    MACROS
 ******************************************************************************/
 /** log macro */
#ifndef LOG_TAG
#define LOG_TAG "none" 
#endif

#ifndef LOGE 
#define LOGE(param, ...) RGLOG(dog::LogLevel::kError, param, ##__VA_ARGS__)
#endif

#ifndef LOGI
#define LOGI(param, ...) RGLOG(dog::LogLevel::kInfo, param, ##__VA_ARGS__)
#endif

#ifndef LOGD
#define LOGD(param, ...) RGLOG(dog::LogLevel::kDebug, param, ##__VA_ARGS__)
#endif

#ifndef LOGW
#define LOGW(param, ...) RGLOG(dog::LogLevel::kWarning, param, ##__VA_ARGS__)
#endif

#ifndef RGLOG
/**%s[%s][%s][%s][%s.%d]: timestamp, log type, module, sub module, func, line */
/** type: short string for debug level */
#define RGLOG(level, param, ...) \
        dog::Logger::getInstance().logPrint(level, LOG_TAG, __FUNCTION__,\
                                       __LINE__, param, ##__VA_ARGS__)

#endif


#ifndef TRACE_IN
#define TRACE_IN() LOGD("+")
#endif

#ifndef TRACE_OUT
#define TRACE_OUT() LOGD("-")
#endif

/******************************************************************************
 **    TYPE DEFINITIONS
 ******************************************************************************/
namespace dog
{
/** log level */
enum class LogLevel:uint8_t
{
    kError = 0,
    kWarning,
    kInfo,
    kDebug,
};

using LogCallbackFunc = std::function<void(LogLevel, /** log level */
                                      const char*, /** tag/context name */
                                      const char*, /** the name of log called function */
                                      int,         /** the line number of log called */
                                      const char*  /** the content of log */
                                      )>;

/******************************************************************************
 **    CLASSES/FUNCTIONS DEFINITIONS
 ******************************************************************************/

 /** log class */
class DOG_CLASS Logger  final
{
protected:
    Logger();
public:
    ~Logger();
public:
    void initialize(LogLevel defaultLevel, ConstString& moduleName, LogCallbackFunc cbFunc = nullptr);
    void setDefaultLevel(LogLevel mll);

    LogLevel getDefaultLevel();
    ConstString& getModuleName();

    void enableTimestamp(bool enable);

    /** todo, add API to filter 'tags' to print or not print */

public:
    void logPrint(LogLevel mll, const char* tag, const char* func, int line, const char* fmt, ...);

    const char* logLevel2ShortStr(LogLevel mll);
    void makeTimestampStr(char buf[], size_t len);

    void makeLogPrefix(char buf[], size_t len, LogLevel mll, const char* tag, const char* func, int line);
public:
    static Logger& getInstance();

private:
    class impl;
    std::unique_ptr<impl> mImpl;
};
} /** namespace dog */

#endif /** !__DOG_LOG_H__ */

